﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;

namespace WebFramework
{
    static class Extensions
    {
        public static List<T> Slice<T>(this IList<T> input, int? start = null, int? end = null, int step = 1)
        {
            if (step == 0) throw new ArgumentException("Step size cannot be zero.", "step");

            if (start == null) start = step > 0 ? 0 : input.Count - 1;
            else if (start < 0) start = start < -input.Count ? 0 : input.Count + start;
            else if (start > input.Count) start = input.Count;

            if (end == null) end = step > 0 ? input.Count : -1;
            else if (end < 0) end = end < -input.Count ? 0 : input.Count + end;
            else if (end > input.Count) end = input.Count;

            if (start == end || start < end && step < 0 || start > end && step > 0) return new List<T>(0);

            var output = new List<T>((int) Math.Ceiling((end - start).Value / (float) step));
            for (int i = start.Value; step > 0 && i < end || step < 0 && i > end; i += step)
                output.Add(input[i]);
            return output;
        }

        public static string Repeat(this string str, int count)
        {
            return new StringBuilder(str.Length * count).Insert(0, str, count).ToString();
        }

        public static bool IsEscaped(this string str, int index)
        {
            bool escaped = false;
            while (index > 0 && str[--index] == '\\') escaped = !escaped;
            return escaped;
        }

        public static bool IsEscaped(this StringBuilder str, int index)
        {
            return str.ToString().IsEscaped(index);
        }

        public static HashSet<T> ToSet<T>(this IEnumerable<T> collection)
        {
            return new HashSet<T>(collection);
        }

        public static HashSet<T> Subtract<T>(this HashSet<T> set, IEnumerable<T> other)
        {
            var copy = set.ToSet();
            copy.ExceptWith(other);
            return copy;
        }

        public static bool InSet<T>(this T item, ISet<T> set)
        {
            return set.Contains(item);
        }

        public static HashSet<T> Intersect<T>(this HashSet<T> set, IEnumerable<T> other)
        {
            var copy = set.ToSet();
            copy.IntersectWith(other);
            return copy;
        }

        public static string Join(this IEnumerable<string> values, string separator)
        {
            return string.Join(separator, values);
        }

        public static char? Get(this string str, int index)
        {
            if (index < 0) index += str.Length;
            if (index >= 0 && index < str.Length) return str[index];
            return null;
        }

        public static T IList<T>(this IList<T> list, int index)
        {
            if (index < 0) index += list.Count;
            if (index < 0 || index >= list.Count) throw new ArgumentOutOfRangeException("index");
            return list[index];
        }
    }
}